package com.redside.webapp.taglib;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.displaytag.tags.el.ExpressionEvaluator;
import org.springframework.context.ApplicationContext;

import com.redside.Constants;
import com.redside.dao.OptionsBeanLookupDao;
import com.redside.model.LabelValue;
import com.redside.model.list.OptionsBean;
import com.redside.webapp.util.AppContext;

/**
 * Tag for creating multiple &lt;select&gt; options for displaying a list of
 * county names.
 * 
 * <p>
 * <b>NOTE</b> - This tag requires a Java2 (JDK 1.2 or later) platform.
 * </p>
 * 
 * @author Peter Chapman
 * @version $Revision: 1.6 $ $Date: 2006/07/15 11:57:20 $
 * 
 * @jsp.tag name="county" bodycontent="empty"
 */
public class CountyTag extends TagSupport {
	private static final long serialVersionUID = 3905528206810167095L;
	protected final transient Log logger = LogFactory.getLog(getClass());
	private String name;
	private String prompt;
	private String scope;
	private String selected;
	private OptionsBeanLookupDao optionsBeanDao = null;

	/**
	 * @param name
	 *            The name to set.
	 * 
	 * @jsp.attribute required="false" rtexprvalue="true"
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @param prompt
	 *            The prompt to set.
	 * @jsp.attribute required="false" rtexprvalue="true"
	 */
	public void setPrompt(String prompt) {
		this.prompt = prompt;
	}

	/**
	 * @param selected
	 *            The selected option.
	 * @jsp.attribute required="false" rtexprvalue="true"
	 */
	public void setDefault(String selected) {
		this.selected = selected;
	}

	/**
	 * Property used to simply stuff the list of counties into a specified
	 * scope.
	 * 
	 * @param scope
	 * 
	 * @jsp.attribute required="false" rtexprvalue="true"
	 */
	public void setToScope(String scope) {
		this.scope = scope;
	}

	/**
	 * Process the start of this tag.
	 * 
	 * @return int status
	 * 
	 * @exception JspException
	 *                if a JSP exception has occurred
	 * 
	 * @see javax.servlet.jsp.tagext.Tag#doStartTag()
	 */
	public int doStartTag() throws JspException {
		ExpressionEvaluator eval = new ExpressionEvaluator(this, pageContext);

		if (selected != null) {
			selected = eval.evalString("default", selected);
		}

		logger.debug("===========CountyTag=============");

		List<OptionsBean> countyList = null;
		try {
			logger.debug("getting sql");
			ApplicationContext ctx = AppContext.getApplicationContext();
			optionsBeanDao = (OptionsBeanLookupDao) ctx
					.getBean("optionsBeanLookupDao");
			countyList = optionsBeanDao.findAll(Constants.COUNTY_LIST);
		} catch (Exception e) {
			e.printStackTrace();
		}
		List<LabelValue> counties = this.buildCountyList(countyList);
		logger.debug("counties: " + counties.size());
		if (scope != null) {
			if (scope.equals("page")) {
				pageContext.setAttribute(name, counties);
			} else if (scope.equals("request")) {
				pageContext.getRequest().setAttribute(name, counties);
			} else if (scope.equals("session")) {
				pageContext.getSession().setAttribute(name, counties);
			} else if (scope.equals("application")) {
				pageContext.getServletContext().setAttribute(name, counties);
			} else {
				throw new JspException(
						"Attribute 'scope' must be: page, request, session or application");
			}
		} else {
			StringBuffer sb = new StringBuffer();
			sb.append("<select name=\"" + name + "\" id=\"" + name
					+ "\" class=\"select\">\n");

			if (prompt != null) {
				sb.append("    <option value=\"\" selected=\"selected\">");
				sb.append(eval.evalString("prompt", prompt) + "</option>\n");
			}

			for (Iterator i = counties.iterator(); i.hasNext();) {
				LabelValue county = (LabelValue) i.next();
				sb.append("    <option value=\"" + county.getValue() + "\"");

				if ((selected != null) && selected.equals(county.getValue())) {
					sb.append(" selected=\"selected\"");
				}

				sb.append(">" + county.getLabel() + "</option>\n");
			}

			sb.append("</select>");

			try {
				pageContext.getOut().write(sb.toString());
			} catch (IOException io) {
				throw new JspException(io);
			}
		}

		return super.doStartTag();
	}

	/**
	 * Release aquired resources to enable tag reusage.
	 * 
	 * @see javax.servlet.jsp.tagext.Tag#release()
	 */
	public void release() {
		super.release();
	}

	/**
	 * Build a List of LabelValues for all the available counties. Uses the
	 * three letter county id as the value and the county name as the label.
	 * 
	 * @param locale
	 *            The Locale used to localize the county names.
	 * 
	 * @return List of LabelValues for all available countries.
	 */
	protected List<LabelValue> buildCountyList(List<OptionsBean> countyList) {
		final String EMPTY = "";
		List<LabelValue> counties = new ArrayList<LabelValue>();

		for (int i = 0; i < countyList.size(); i++) {
			OptionsBean county = (OptionsBean) countyList.get(i);
			final String id = county.getId();
			final String name = county.getValue();
			if (!EMPTY.equals(id) && !EMPTY.equals(name)) {
				LabelValue countLabel = new LabelValue(name, id);

				if (!counties.contains(countLabel)) {
					counties.add(new LabelValue(name, id));
				}
			}
		}
		Collections.sort(counties, new LabelValueComparator(countyList));
		return counties;
	}

	/**
	 * Class to compare LabelValues using their labels with locale-sensitive
	 * behaviour.
	 */
	public class LabelValueComparator implements Comparator {

		/**
		 * Creates a new LabelValueComparator object.
		 * 
		 * @param list
		 *            , the List used for localized String comparison.
		 */
		public LabelValueComparator(List<OptionsBean> list) {
			// c = Collator.getInstance(list);
		}

		/**
		 * Compares the localized labels of two LabelValues.
		 * 
		 * @param o1
		 *            The first LabelValue to compare.
		 * @param o2
		 *            The second LabelValue to compare.
		 * 
		 * @return The value returned by comparing the localized labels.
		 */
		public final int compare(Object o1, Object o2) {
			LabelValue lhs = (LabelValue) o1;
			LabelValue rhs = (LabelValue) o2;
			return lhs.getLabel().compareTo(rhs.getLabel());
		}
	}
}
